//{
/**
 * @fileOverview This file contains Husky plugin with test handlers
 * @name hp_SE2M_StyleRemover.js
 */
nhn.husky.SE2M_StyleRemover = jindo.$Class({
	name: "SE2M_StyleRemover",

	$ON_MSG_APP_READY : function(){
		this.oApp.exec("REGISTER_UI_EVENT", ["styleRemover", "click", "CHOOSE_REMOVE_STYLE", []]);
	},

	$LOCAL_BEFORE_FIRST : function(){
		// The plugin may be used in view and when it is used there, EditingAreaManager plugin is not loaded.
		// So, get the document from the selection instead of EditingAreaManager.
		this.oHuskyRange = this.oApp.getEmptySelection();
		this._document = this.oHuskyRange._document;
	},
	
	$ON_CHOOSE_REMOVE_STYLE : function(oSelection){
		var bSelectedBlock = false;
		var htSelectedTDs = {};
		this.oApp.exec("IS_SELECTED_TD_BLOCK",['bIsSelectedTd',htSelectedTDs]);
		bSelectedBlock = htSelectedTDs.bIsSelectedTd;

		if( bSelectedBlock ){
			this.oApp.exec("REMOVE_STYLE_IN_BLOCK", []);
		}else{
			this.oApp.exec("REMOVE_STYLE", []);
		}
		
		this.oApp.exec('MSG_NOTIFY_CLICKCR', ['noeffect']);
	},
	
	$ON_REMOVE_STYLE_IN_BLOCK : function(oSelection){
		var htSelectedTDs = {};
		this.oSelection = this.oApp.getSelection();
		this.oApp.exec("GET_SELECTED_TD_BLOCK",['aTdCells',htSelectedTDs]);
		var aNodes = htSelectedTDs.aTdCells;
		
		for( var j = 0; j < aNodes.length ; j++){
			this.oSelection.selectNodeContents(aNodes[j]);
			this.oSelection.select();
			this.oApp.exec("REMOVE_STYLE", []);
		}
	},
	
	$ON_REMOVE_STYLE : function(oSelection){
		this.oApp.exec("RECORD_UNDO_BEFORE_ACTION", ["remove style"]);

		if(!oSelection || !oSelection.commonAncestorContainer){
			oSelection = this.oApp.getSelection();
		}

		if(oSelection.collapsed){return;}

		oSelection.expandBothEnds();

		var sBookmarkID = oSelection.placeStringBookmark();
		var aNodes = oSelection.getNodes(true);

		this._removeStyle(aNodes);
		oSelection.moveToBookmark(sBookmarkID);

		var aNodes = oSelection.getNodes(true);
		for(var i=0; i<aNodes.length; i++){
			var oNode = aNodes[i];
			
			if(oNode.style && oNode.tagName != "BR" && oNode.tagName != "TD" && oNode.tagName != "TR" && oNode.tagName != "TBODY" && oNode.tagName != "TABLE"){
				oNode.removeAttribute("align");
				oNode.removeAttribute("style");
				if((jindo.$Element(oNode).css("display") == "inline" && oNode.tagName != "IMG" && oNode.tagName != "IFRAME") && (!oNode.firstChild || oSelection._isBlankTextNode(oNode.firstChild))){
					oNode.parentNode.removeChild(oNode);
				}
			}
		}
		
		oSelection.moveToBookmark(sBookmarkID);
		oSelection.select();
		
		// use a custom removeStringBookmark here as the string bookmark could've been cloned and there are some additional cases that need to be considered

		// remove start marker
		var oMarker = this._document.getElementById(oSelection.HUSKY_BOOMARK_START_ID_PREFIX+sBookmarkID);
		while(oMarker){
			oParent = nhn.DOMFix.parentNode(oMarker);
			oParent.removeChild(oMarker);
			while(oParent && (!oParent.firstChild || (!oParent.firstChild.nextSibling && oSelection._isBlankTextNode(oParent.firstChild)))){
				var oNextParent = oParent.parentNode;
				oParent.parentNode.removeChild(oParent);
				oParent = oNextParent;
			}
			oMarker = this._document.getElementById(oSelection.HUSKY_BOOMARK_START_ID_PREFIX+sBookmarkID);
		}

		// remove end marker
		var oMarker = this._document.getElementById(oSelection.HUSKY_BOOMARK_END_ID_PREFIX+sBookmarkID);
		while(oMarker){
			oParent = nhn.DOMFix.parentNode(oMarker);
			oParent.removeChild(oMarker);
			while(oParent && (!oParent.firstChild || (!oParent.firstChild.nextSibling && oSelection._isBlankTextNode(oParent.firstChild)))){
				var oNextParent = oParent.parentNode;
				oParent.parentNode.removeChild(oParent);
				oParent = oNextParent;
			}
			oMarker = this._document.getElementById(oSelection.HUSKY_BOOMARK_END_ID_PREFIX+sBookmarkID);
		}

		this.oApp.exec("RECORD_UNDO_AFTER_ACTION", ["remove style"]);
		this.oApp.exec("CHECK_STYLE_CHANGE");
	},
	
	$ON_REMOVE_STYLE2 : function(aNodes){
		this._removeStyle(aNodes);
	},
	
	$ON_REMOVE_STYLE_AND_PASTE_HTML : function(sHtml){
		if(!sHtml) {return false;}
		if(this.oApp.getEditingMode() != "WYSIWYG"){
			this.oApp.exec("CHANGE_EDITING_MODE", ["WYSIWYG"]);
		}
		var oSelection = this.oApp.getSelection();
		oSelection.deleteContents(); // remove select node - for dummy image, reedit object
		
		// If the table were inserted within a styled(strikethough & etc) paragraph, the table may inherit the style in IE.
		var elDivHolder = this.oApp.getWYSIWYGDocument().createElement("DIV");
		oSelection.insertNode(elDivHolder);
		if (!!jindo.$Agent().navigator().webkit) {
			elDivHolder.innerHTML = "&nbsp;"; // for browser bug! - summary reiteration
		}
		
		oSelection.selectNode(elDivHolder);
		this.oApp.exec("REMOVE_STYLE", [oSelection]);
		
		oSelection.selectNode(elDivHolder);
		oSelection.pasteHTML(sHtml);
				
		oSelection.collapseToEnd(); //파란색 커버 제거.
		oSelection.select();
				
		if (!elDivHolder) {// 임시 div 삭제.
			elDivHolder.parentNode.removeChild(elDivHolder);
		}
	},
	
	_removeStyle : function(aNodes){
		var arNodes = jindo.$A(aNodes);
		for(var i=0; i<aNodes.length; i++){
			var oNode = aNodes[i];

			// oNode had been removed from the document already
			if(!oNode || !oNode.parentNode || !oNode.parentNode.tagName){continue;}
			
			var bDontSplit = false;
			// If oNode is direct child of a block level node, don't do anything. (should not move up the hierarchy anymore)
			if(jindo.$Element(oNode.parentNode).css("display") != "inline"){
				continue;
			}

			var parent = oNode.parentNode;

			// do not proceed if oNode is not completely selected
			if(oNode.firstChild){
				if(arNodes.indexOf(this.oHuskyRange._getVeryLastRealChild(oNode)) == -1){continue;}
				if(arNodes.indexOf(this.oHuskyRange._getVeryFirstRealChild(oNode)) == -1){continue;}
			}

			// Case 1: oNode is the right most node
			//
			// If oNode were C(right most node) from 
			//   H
			//   |
			//   P
			// / | \
			// A B C
			//
			// and B and C were selected, bring up all the (selected) left siblings to the right of the parent and and make it
			//   H
			// / | \
			// P B C
			// |
			// A
			// ===========================================================
			// If A, B and C were selected from 
			//   H
			//   |
			//   P
			// / | \
			// A B C
			//
			// append them to the right of the parent and make it
			//    H
			// / | | \
			// P A B C
			//
			// and then remove P as it's got no child and make it
			//   H
			// / | \
			// A B C
			if(!oNode.nextSibling){
				i--;
				var tmp = oNode;
				// bring up left siblings
				while(tmp){
					var prevNode = tmp.previousSibling;
					parent.parentNode.insertBefore(tmp, parent.nextSibling);
					if(!prevNode){break;}
					if(arNodes.indexOf(this._getVeryFirst(prevNode)) == -1){break;}
					tmp = prevNode;
				}

				// remove the parent if it's got no child now
				if(parent.childNodes.length === 0){parent.parentNode.removeChild(parent);}

				continue;
			}
			
			// Case 2: oNode's got a right sibling that is included in the selection
			//
			// if the next sibling is included in the selection, stop current iteration
			// -> current node will be handled in the next iteration
			if(arNodes.indexOf(this._getVeryLast(oNode.nextSibling)) != -1){continue;}

			// Since the case
			// 1. oNode is the right most node
			// 2. oNode's got a right sibling that is included in the selection
			// were all taken care of above, so from here we just need take care of the case when oNode is NOT the right most node and oNode's right sibling is NOT included in the selection

			// Case 3: the rest
			// When all of the left siblings were selected, take all the left siblings and current node and append them to the left of the parent node.
			//    H
			//    |
			//    P
			// / | | \
			// A B C D
			// -> if A, B and C were selected, then make it
			//    H
			// / | | \
			// A B C P
			//       |
			//       D
			i--;
			// bring up selected prev siblings
			if(arNodes.indexOf(this._getVeryFirst(oNode.parentNode)) != -1){
				// move
				var tmp = oNode;
				var lastInserted = parent;
				while(tmp){
					var prevNode = tmp.previousSibling;
					parent.parentNode.insertBefore(tmp, lastInserted);
					lastInserted = tmp;
					
					if(!prevNode){break;}
					tmp = prevNode;
				}
				if(parent.childNodes.length === 0){parent.parentNode.removeChild(parent);}
			// When NOT all of the left siblings were selected, split the parent node and insert the selected nodes in between.
			//    H
			//    |
			//    P
			// / | | \
			// A B C D
			// -> if B and C were selected, then make it
			//    H
			// / | | \
			// P B C P
			// |     |
			// A     D
			}else{
				//split
				if(bDontSplit){
					i++;
					continue;
				}
				
				var oContainer = this._document.createElement("SPAN");
				var tmp = oNode;
				parent.insertBefore(oContainer, tmp.nextSibling);
				while(tmp){
					var prevNode = tmp.previousSibling;
					oContainer.insertBefore(tmp, oContainer.firstChild);

					if(!prevNode){break;}
					if(arNodes.indexOf(this._getVeryFirst(prevNode)) == -1){break;}
					tmp = prevNode;
				}
				
				this._splitAndAppendAtTop(oContainer);
				while(oContainer.firstChild){
					oContainer.parentNode.insertBefore(oContainer.firstChild, oContainer);
				}
				oContainer.parentNode.removeChild(oContainer);
			}
		}
	},

	_splitAndAppendAtTop : function(oSpliter){
		var targetNode = oSpliter;
		var oTmp = targetNode;
		var oCopy = oTmp;

		while(jindo.$Element(oTmp.parentNode).css("display") == "inline"){
			var oNode = oTmp.parentNode.cloneNode(false);

			while(oTmp.nextSibling){
				oNode.appendChild(oTmp.nextSibling);
			}

			oTmp = oTmp.parentNode;

			oNode.insertBefore(oCopy, oNode.firstChild);
			oCopy = oNode;
		}

		oTop = oTmp.parentNode;
		oTop.insertBefore(targetNode, oTmp.nextSibling);
		oTop.insertBefore(oCopy, targetNode.nextSibling);
	},
	
	_getVeryFirst : function(oNode){
		if(!oNode){return null;}

		if(oNode.firstChild){
			return this.oHuskyRange._getVeryFirstRealChild(oNode);
		}else{
			return oNode;
		}
	},
	
	_getVeryLast : function(oNode){
		if(!oNode){return null;}
	
		if(oNode.lastChild){
			return this.oHuskyRange._getVeryLastRealChild(oNode);
		}else{
			return oNode;
		}
	}
});
//}
